/*
缓冲区类: 直接存放格式化后的日志消息字符串
    - 减少LogMsg对象频繁的构造消耗
    - 针对缓冲区中的日志消息, 进行一次性IO操作
设计思想:
    1. 管理存放字符串数据的缓冲区(技术选型: vector)
    2. 写指针指向可写区域的起始位置(避免数据覆盖)
    3. 读指针指向可读区域的起始位置(当读指针到达写指针的位置, 表示可读数据已经取出)
操作:
    1. 向缓冲区中写入数据
    2. 获取可读数据的起始地址
    3. 获取可读数据长度
    4. 移动读写指针
    5. 初始化缓冲区
    6. 交换缓冲区(交换空间地址而不是交换空间内的数据)
*/
#ifndef __M_BUFF_H__
#define __M_BUFF_H__
#define BUFF_DEFAULT_SIZE (1 * 1024 * 1024)
#define BUFF_THRESHOLD_SIZE (4 * 1024 * 1024) // 小于阈值,翻倍增长; 达到阈值,线性增长
#define BUFF_INCREMENT_SIZE (1 * 1024 * 1024) // 线性增长的增量
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <mutex>
#include <cassert>
namespace LOG
{
    class Buffer
    {
    public:
        Buffer() : _reader_idx(0), _writer_idx(0), _v(BUFF_DEFAULT_SIZE) {}
        // 判断可读区域是否为空
        bool empty() { return _reader_idx == _writer_idx; }
        // 获取可读区域的大小
        size_t readAbleSize() { return _writer_idx - _reader_idx; }
        // 获取剩余可写区域的大小
        size_t writeAbleSize() { return _v.size() - _writer_idx; }

        void reset() { _reader_idx = _writer_idx = 0; }
        // 交换空间
        void swap(Buffer &buf)
        {
            _v.swap(buf._v);
            std::swap(_reader_idx, buf._reader_idx);
            std::swap(_writer_idx, buf._writer_idx);
        }
        // 存入数据-->写入数据TODO
        void push(const char *data, size_t len)
        {
            // 缓冲区剩余空间不足: 1.扩容 2.阻塞
            // if (len > writeAbleSize())
            //     return; // 可写空间不足, 直接阻塞返回[固定大小]
            // 扩容用于极限性能测试
            ensureEnoughSpace(len);
            //  1. 将数据拷贝进缓冲区
            // printf("push:%s\n",data);
            std::copy(data, data + len, &_v[_writer_idx]);
            // 2. 将当前写入位置向后偏移
            //_writer_idx += len;
            moveWriter(len);
            // printf("push-copy:%s\n",begin());
        }

        //  取出数据-->读取数据
        void pop(size_t len)
        {
            _reader_idx += len;
            assert(_reader_idx <= _writer_idx);
        }
        // 获取可读数据的起始位置
        const char *begin() { return &_v[_reader_idx]; }
        void moveReader(size_t len)
        {
            assert(len <= readAbleSize());
            _reader_idx += len;
        }

    protected:
        void moveWriter(size_t len)
        {
            assert((len + _writer_idx) <= _v.size());
            _writer_idx += len;
        }

        // push操作: 对缓冲区空间进行扩容操作-->先翻倍增长, 再线性增长
        void ensureEnoughSpace(size_t len)
        {
            if (len <= writeAbleSize())
                return; // 不需要扩容
            size_t new_size = 0;
            if (_v.size() < BUFF_THRESHOLD_SIZE)
            {
                new_size = _v.size() * 2 + len; // 指数增长
            }
            else
            {
                new_size = _v.size() + BUFF_INCREMENT_SIZE + len; // 线性增长
            }
            _v.resize(new_size);
        }

    private:
        // 读指针(下标):指向可读区域的起始地址
        size_t _reader_idx;
        // 写指针(下标):指向可写区域的起始地址
        size_t _writer_idx;
        // 存放字符串数据的缓冲区
        std::vector<char> _v;
    };
}
#endif
